package com.yhq.basic.thread.lock;

import com.yhq.basic.jvm.dataarea.po.Person;
import org.openjdk.jol.info.ClassLayout;

/**
 * 多线程竞争同一把锁，没有抢到锁的线程进入blocking状态，等抢到锁的线程执行完成再唤醒该线程。
 * 实现原理：JVM内置锁，基于Monitor机制实现，依赖操作系统的互斥原语 Mutex(互斥量)，重量级锁，
 * 在1.5之后做了重大优化，比如锁粗化，锁消除，轻量级锁，偏向锁，自适应自旋等，内置锁的并发性能已经可以和Lock持平
 * 1.锁粗化：在jvm JIT编译阶段，加大锁的范围，防止锁重入；
 * 2.锁消除：在jvm JIT编译阶段，一直一个线程使用，且作用域只在一个方法里面(使用逃逸分析+标量替换)，则直接消除；
 * 3.自适应自旋（CAS）:
 * 4.01 偏向锁：一直只有一个线程，锁的作用域不满足锁消除的原则，则使该锁一直偏向该线程；jvm默认4秒后自动开启偏向锁；
 * 5.00 轻量级锁：有多个线程交替执行，不存在锁竞争的情况，则变成轻量级锁；
 * 6.10 重量级锁：多线程竞争；
 * @author hqyin
 * @date 2025/5/6 5:48 PM
 */
public class Demo1Synchronized {

    public static void main(String[] args) throws InterruptedException {
        //方法加synchronized 是在access_flags中设置ACC_SYNCHRONIZED标记实现的
//        Demo1Synchronized.show1();

        //同步代码块是通过monitorenter和monitorexit

        //测试锁粗化
//        long start1 = System.currentTimeMillis();
//        for (int i = 0; i < 100000000; i++) {
//            test_nolockCoarsening();
//        }
//        long end1 = System.currentTimeMillis();
//        System.out.println("锁未粗化，耗时："+(end1-start1));
//
//        long start2 = System.currentTimeMillis();
//        test_lockCoarsening();
//        long end2 = System.currentTimeMillis();
//        System.out.println("锁粗化，耗时："+(end2-start2));
        //锁消除
//        long start3 = System.currentTimeMillis();
//        test_lockElimination();
//        long end3 = System.currentTimeMillis();
//        System.out.println("锁消除，耗时："+(end3-start3));

        //锁升级
        //轻量级锁CAS失败，则会升级为重量级锁
//        test_lockUpgrade();

        //偏向锁撤销场景 轻量级锁在栈中保存了markword，有hashcode，重量级锁在monitor中保存了hashcode
        //场景一：偏向锁撤销场景，hashCode调用，在匿名偏向锁调的情况下，锁对象调用hashCode，会变成无锁状态，再加锁会变成轻量级锁
//        test_biasable_hashCode_demo1();

        //场景2：偏向锁撤销场景，hashCode调用，在指定特定偏向锁的代码块中，锁对象调用hashCode，会变成重量级锁
        test_biasable_hashCode_demo2();
        //场景3：偏向锁撤销场景，wait/notify，会变成重量级锁
//        test_biasable_hashCode_demo2();

    }

    /**
     * 场景一：偏向锁撤销场景，hashCode调用，在指定特定偏向锁的代码块中，锁对象调用hashCode，会变成重量级锁
     */
    private static void test_biasable_hashCode_demo2() throws InterruptedException {
        System.out.println("无锁状态（01）："+ClassLayout.parseInstance(new Object()).toPrintable());
        //jvm 默认4s后自动开启轻量级锁,可通过-XX:BiasedLockingStartupDelay=0取消延迟
        //如果不要偏向锁，可通过-XX:UseBiasedLocking=false来设置
        Thread.sleep(5000);
        Person person = new Person();
        System.out.println("偏向锁（101）："+ClassLayout.parseInstance(person).toPrintable());
        synchronized (person) {
            //偏向锁执行过程中调用hashCode
            person.hashCode();
            System.out.println("重量级锁（10）："+ClassLayout.parseInstance(person).toPrintable());
            new StringBuffer().append("11").append("22");
        }

        Thread.sleep(5000);
        System.out.println("无锁状态（01）："+ClassLayout.parseInstance(person).toPrintable());


    }

    /**
     *
     * 场景一：偏向锁撤销场景，hashCode调用，在匿名偏向锁调的情况下，锁对象调用hashCode，会变成无锁状态，再加锁会变成轻量级锁
     * @throws InterruptedException
     */
    private static void test_biasable_hashCode_demo1() throws InterruptedException {
        Person person = new Person();
        System.out.println("无锁状态（01）："+ClassLayout.parseInstance(person).toPrintable());
        //jvm 默认4s后自动开启轻量级锁,可通过-XX:BiasedLockingStartupDelay=0取消延迟
        //如果不要偏向锁，可通过-XX:UseBiasedLocking=false来设置
        Thread.sleep(5000);
        //如果锁对象调用了hashCode还会开启偏向锁吗？
        person.hashCode();
        System.out.println("无锁状态（01）："+ClassLayout.parseInstance(person).toPrintable());
        synchronized (person) {
            System.out.println("轻量级锁（00）："+ClassLayout.parseInstance(person).toPrintable());
        }

        Thread.sleep(5000);
        System.out.println("无锁状态（01）："+ClassLayout.parseInstance(person).toPrintable());

    }

    /**
     * 要想展示轻量级锁，先把偏向锁代码注释掉
     * @throws InterruptedException
     */
    private static void test_lockUpgrade() throws InterruptedException {
        Person tmpPerson = new Person();

        System.out.println("无锁状态（01）："+ClassLayout.parseInstance(tmpPerson).toPrintable());
        //jvm 默认4s后自动开启轻量级锁,可通过-XX:BiasedLockingStartupDelay=0取消延迟
        //如果不要偏向锁，可通过-XX:UseBiasedLocking=false来设置
        Thread.sleep(5000);
        Person person = new Person();
        System.out.println("匿名偏向锁（101）："+ClassLayout.parseInstance(person).toPrintable());
        synchronized (person) {
            System.out.println("已指定特定线程的偏向锁（101）："+ClassLayout.parseInstance(person).toPrintable());
        }

        //

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (person) {
                    System.out.println("轻量级锁（00）："+ClassLayout.parseInstance(person).toPrintable());
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }

            }
        }).start();

        Thread.sleep(1000);
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (person) {
                    System.out.println("重量级锁（10）："+ClassLayout.parseInstance(person).toPrintable());
                }
            }
        }).start();


        Thread.sleep(5000);
        System.out.println("无锁状态（01）-释放锁："+ClassLayout.parseInstance(person).toPrintable());

    }


    private static Object obj = new Object();



    public static synchronized void show1(){
    }

    /**
     *
     * -XX:+EliminateLocks:开启锁消除，默认开启
     * -XX:-EliminateLocks
     */
    private static void test_lockElimination() {
        for (int i = 0; i < 100000000; i++) {
            StringBuffer buffer = new StringBuffer();
            buffer.append("hahah").append("bbb");
        }
    }

    private static void test_nolockCoarsening() {
        synchronized (obj) {
            int i = 1;
        }
    }

    private static void test_lockCoarsening() {
        synchronized (obj) {
            for (int i = 0; i < 100000000; i++) {
                int b = 1;
            }
        }
    }

    public synchronized void show2(){

    }

    public void show3() {
        synchronized (this) {
            System.out.println(1);
        }
    }
}
